import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.json.simple.JSONObject;

/**
 * Singleton class for interfacing with the Graphical user interface
 *
 */
public class DataProcessor {
	
	private static DataProcessor instance = null;
	private Map <JSONObject, List<JSONObject>> infoMap;
	private static final String URL_PATH_PRE = "http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/";
	private static final String URL_PATH_POST = "/?v=source";
	
	private static final String [] REVISION_NUMBERS = new String [] {"1.5_r4", "1.6_r2", "2.0_r1", "2.1_r2", "2.2.1_r1", "2.2.2_r1", "2.2_r1.1", "2.3.1_r1",
		"2.3.2_r1", "2.3.3_r1", "2.3.4_r1", "2.3.5_r1", "2.3.6_r1", "2.3.7_r1", "2.3_r1", "4.0.1_r1", "4.0.2_r1", "4.0.3_r1", "4.0.4_r1.2", "4.0.4_r2.1", 
		"4.1.1_r1", "4.1.2_r1", "4.2.1_r1.2", "4.2.2_r1", "4.2_r1", "4.3_r1", "4.3_r2.1"};
	
	public DataProcessor () {
		infoMap = new HashMap<JSONObject, List<JSONObject>> ();
	}
	
	public static DataProcessor getInstance() {
		if(instance == null) {
			instance = new DataProcessor();
		}
		
		return instance;
	}
	
	/**
	 * Primary method for interfacing with the graphical user interface
	 * Gets the fileURL as a parameter, finds the file from the grepcode website,
	 * parses the file and interprets it. Builds a map to contain all the necessary information
	 * @param fileURL The android package, class name and revision number concatenated together
	 * @return A map containing a JSON Object as a key. The key contains the class name and class char count
	 *		   The value is a list of JSONObject which contains information about the keys
	 */
	public  Map<JSONObject, List<JSONObject>> getClassMethodLineNumbers (String fileURL) {
		String fileName = parseClassAndRevisionName(fileURL);
		Map <JSONObject, List<JSONObject>> resultMap = new HashMap<JSONObject, List<JSONObject>> ();
		
		boolean inPrev = false;
		Set <JSONObject >prevVersionKeySet  = infoMap.keySet();
		for(JSONObject prevKey : prevVersionKeySet) {
			if(prevKey.containsValue(fileName))
			{
				resultMap.put(prevKey, infoMap.get(prevKey));
				inPrev = true;
				break;
				
			}
		}
		if(!inPrev) {
			List <JSONObject> prevVersion = findPreviousVersion(fileName);
			File file = getFileFromURL(URL_PATH_PRE + fileURL + URL_PATH_POST, fileName);
			file.deleteOnExit();
			Parser parser = new Parser();
			Interpreter interpreter = new Interpreter (); 
			resultMap =  interpreter.interpret(parser.parse(file), prevVersion);
			infoMap.putAll(resultMap);
		}
		
		return resultMap;
	}
	
	/**
	 * Gets the file from a URL and a specified file name
	 * @param fileURL the file URL to be read from
	 * @param fileName the name of the file
	 * @return The file from the specified URL and file name
	 */
	private File getFileFromURL(String fileURL, String fileName) {
		URLFileReader urlReader = new URLFileReader();
		File file = urlReader.readFromURL(fileURL, fileName);
		return file;
	}
	
	/**
	 * Cuts up unnecessary information from the URL to give a name to the class when packaged into the map
	 * @param fileURL The file URL passed in from the GUI
	 * @return The name of the class
	 */
	private String parseClassAndRevisionName(String fileURL) {
		String revisionNumber = fileURL.substring(0, fileURL.indexOf('/'));
		String className = fileURL.substring(fileURL.lastIndexOf('/') + 1, fileURL.lastIndexOf('.'));
		return className + ".java" + "-" + revisionNumber;
	}
	
	/**
	 * Finds the previous version of the class in a list of previous versions held in the class
	 * @param fileName The name of the file that will be used to find the previous class
	 * @return A list of JSON Objects from the previous version of the class
	 */
	private List<JSONObject> findPreviousVersion (String fileName) {
		List <JSONObject> prevRevision = null;
		String revisionNumber = fileName.substring(fileName.indexOf('-') + 1);
		if (!revisionNumber.equals("1.5_r4")) {
			for(int i = 0; i < REVISION_NUMBERS.length; i++) {
				boolean foundPrev = false;
				if(REVISION_NUMBERS[i].equals(revisionNumber)) {
					String prevRevisionName = fileName.substring(0, fileName.indexOf('-')) + "-" + REVISION_NUMBERS[i - 1];
					for(Map.Entry<JSONObject, List<JSONObject>> entry : infoMap.entrySet()) {
						JSONObject classInfo = entry.getKey();
						if(classInfo.get("Class Name").equals(prevRevisionName)) {
							prevRevision = infoMap.get(classInfo);
							foundPrev = true;
							break;
						}
					}
					if(foundPrev) {
						break;
					}
				}
			}
		}
		return prevRevision;
		
	}

}
